package testing;

import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;

import dse.BloomFilter;
import dse.Cluster;
import dse.DataObject;
import dse.DataObjectAccessRanking;
import dse.Network;
import dse.Node;
import dse.Pair;

public class SpecializedRequestScheduler
extends dse.modules.GeneralRequestEventScheduler
{
	public int requestsToMakeCount = 1;
	public int requestPeriodDelay = 10;
	public DataObject dobj = null;
	public Cluster dobjCachedIn = null;
	
	private int requestsTaken = 0;
	private int period = 0;
	
	private Vector<Pair<Node,DataObject>> requestsToMake;
	
	
	public void initalizeRequests (
			Network network,
			Map<Cluster, DataObjectAccessRanking> accessRankings
			)
	{
		if (requestsToMake != null)
			return;
 
		requestsToMake = new Vector<Pair<Node,DataObject>>(requestsToMakeCount);
		
		for (int a = 0; a < requestsToMakeCount; a++) {
			Pair<Node,DataObject> requestToMake = null;
			while (requestToMake == null) {
				Map<Node, DataObject> m = 
					super.getRequests(network, accessRankings);
				for (Node n : m.keySet()) {
					if (inNeighborhood(network, n)) {
						// This doesnt have to be true yet!
						BloomFilter<DataObject> bf = 
							dobjCachedIn.bloomFilter().clone();
						bf.add(dobj); // note this can be invalid!
						Cluster c = network.lookupCluster(n.clusterId());
						c.refreshBloomFilter(dobjCachedIn, bf);
						requestToMake = new Pair<Node,DataObject>(n, dobj);
						break;
					}
				}
			}
			requestsToMake.add(requestToMake);
		}
	}
	
	
	public Map<Node, DataObject> getRequests (
			Network network,
			Map<Cluster, DataObjectAccessRanking> accessRankings
			)
	{
		period++;
		
		if (requestsToMake == null) 
			initalizeRequests(network, accessRankings);
		if ((period / (double)requestPeriodDelay - 1) >= requestsTaken 
				&& requestsToMake.size() > requestsTaken)
		{
			// Take new requests
			Pair<Node,DataObject> requestToMake = 
				requestsToMake.elementAt(requestsTaken);
			
			requestsTaken++;
			
			Map<Node,DataObject> onlyOne = new Hashtable<Node, DataObject>();
			onlyOne.put(requestToMake.first, requestToMake.second);
			return onlyOne;
		}
		
		return new Hashtable<Node, DataObject>();
	}
	
	private boolean inNeighborhood (Network network, Node node)
	{
		Cluster c = network.lookupCluster(node.clusterId());
		for (Cluster nc : c.neighborhood()) {
			if (nc.id() == dobjCachedIn.id())
				return true;
		}
		return false;
	}
}